{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 1, Topic 2: Clock Glitching to Bypass Password"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "NOTE: This lab references some (commercial) training material on [ChipWhisperer.io](https://www.ChipWhisperer.io). You can freely execute and use the lab per the open-source license (including using it in your own courses if you distribute similarly), but you must maintain notice about this source location. Consider joining our training course to enjoy the full experience.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**SUMMARY:** *In the previous lab, we learned how clock glitching can be used to cause a target to behave unexpectedly. In this lab, we'll look at a slightly more realistic example - glitching past a password check*\n",
    "\n",
    "**LEARNING OUTCOMES:**\n",
    "\n",
    "* Applying previous glitch settings to new firmware\n",
    "* Checking for success and failure when glitching"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Firmware\n",
    "\n",
    "We've already seen how we can insert clock gliches to mess up a calculation that a target is trying to make. While this has many applications, some which will be covered in Fault_201, let's take a look at something a little closer to our original example of glitch vulnerable code: a password check. No need to change out firmware here, we're still using the simpleserial-glitch project (though we'll go through all the build stuff again).\n",
    "\n",
    "The code is as follows for the password check:\n",
    "\n",
    "```C\n",
    "uint8_t password(uint8_t* pw)\n",
    "{\n",
    "    char passwd[] = \"touch\";\n",
    "    char passok = 1;\n",
    "    int cnt;\n",
    "\n",
    "    trigger_high();\n",
    "\n",
    "    //Simple test - doesn't check for too-long password!\n",
    "    for(cnt = 0; cnt < 5; cnt++){\n",
    "        if (pw[cnt] != passwd[cnt]){\n",
    "            passok = 0;\n",
    "        }\n",
    "    }\n",
    "    \n",
    "    trigger_low();\n",
    "    \n",
    "    simpleserial_put('r', 1, (uint8_t*)&passok);\n",
    "    return passok;\n",
    "}\n",
    "```\n",
    "\n",
    "There's really nothing out of the ordinary here - it's just a simple password check. We can communicate with it using the `'p'` command."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'OPENADC'\n",
    "PLATFORM = 'CWLITEARM'\n",
    "SS_VER = 'SS_VER_2_1'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PLATFORM\" \"$SS_VER\"\n",
    "cd ../../../firmware/mcu/simpleserial-glitch\n",
    "make PLATFORM=$1 CRYPTO_TARGET=NONE SS_VER=$2 -j"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run \"../../Setup_Scripts/Setup_Generic.ipynb\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fw_path = \"../../../firmware/mcu/simpleserial-glitch/simpleserial-glitch-{}.hex\".format(PLATFORM)\n",
    "cw.program_target(scope, prog, fw_path)\n",
    "if SS_VER == 'SS_VER_2_1':\n",
    "    target.reset_comms()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def reboot_flush():\n",
    "    reset_target(scope)\n",
    "    #Flush garbage too\n",
    "    target.flush()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we send a wrong password:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Do glitch loop\n",
    "reboot_flush()pw = bytearray([0x00]*5)\n",
    "target.simpleserial_write('p', pw)\n",
    "\n",
    "val = target.simpleserial_read_witherrors('r', 1, glitch_timeout=10)#For loop check\n",
    "valid = val['valid']\n",
    "if valid:\n",
    "    response = val['payload']\n",
    "    raw_serial = val['full_response']\n",
    "    error_code = val['rv']\n",
    "\n",
    "print(val)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We get a response of zero. But if we send the correct password:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Do glitch loop\n",
    "reboot_flush()pw = bytearray([0x74, 0x6F, 0x75, 0x63, 0x68]) # correct password ASCII representation\n",
    "target.simpleserial_write('p', pw)\n",
    "\n",
    "val = target.simpleserial_read_witherrors('r', 1, glitch_timeout=10)#For loop check\n",
    "valid = val['valid']\n",
    "if valid:\n",
    "    response = val['payload']\n",
    "    raw_serial = val['full_response']\n",
    "    error_code = val['rv']\n",
    "\n",
    "print(val)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We get a 1 back. Set the glitch up as in the previous part:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.cglitch_setup()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Update the code below to also add an ext offset parameter:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc = cw.GlitchController(groups=[\"success\", \"reset\", \"normal\"], parameters=[\"width\", \"offset\", \"ext_offset\"])\n",
    "gc.display_stats()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Like before, we'll plot our settings. The plot is 2D, so you'll need to make a decision about what to plot. In this case, we'll plot offset and ext_offset, but pick whichever you like:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc.glitch_plot(plotdots={\"success\":\"+g\", \"reset\":\"xr\", \"normal\":None}, x_index=\"ext_offset\", y_index=\"offset\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And make a glitch loop. Make sure you use some successful settings that you found in the previous lab, since it will make this one much shorter!\n",
    "\n",
    "One change you probably want to make is to add a scan for ext_offset. The number of places we can insert a successful glitch has gone way down. Doing this will also be very important for future labs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tqdm.notebook import tqdm\n",
    "import re\n",
    "import struct\n",
    "gc.set_global_step(step)\n",
    "\n",
    "# replace these with your settings from the last part\n",
    "# The example width/offset settings shown here are for CW-Lite/Pro; width/offset are expressed differently for Husky (see Fault 1_1)\n",
    "gc.set_range(\"width\", ???, ???)\n",
    "gc.set_range(\"offset\", ???, ???)\n",
    "gc.set_global_step(???)\n",
    "\n",
    "# you can leave this range for ext_offset\n",
    "gc.set_range(???, 0, 100)\n",
    "gc.set_step(???, 1)\n",
    "\n",
    "# adjust if you want\n",
    "step = 1\n",
    "\n",
    "scope.glitch.repeat = 1\n",
    "reboot_flush()\n",
    "\n",
    "for glitch_settings in gc.glitch_values():\n",
    "    scope.glitch.offset = ???\n",
    "    scope.glitch.width = ???\n",
    "    scope.glitch.ext_offset = ???\n",
    "    if scope.adc.state:\n",
    "        # can detect crash here (fast) before timing out (slow)\n",
    "        print(\"Trigger still high!\")\n",
    "        gc.add(\"reset\")\n",
    "\n",
    "        #Device is slow to boot?\n",
    "        reboot_flush()\n",
    "\n",
    "    scope.arm()\n",
    "    target.simpleserial_write('p', bytearray(???)) #send an incorrect password\n",
    "\n",
    "    ret = scope.capture()\n",
    "\n",
    "    val = target.simpleserial_read_witherrors('r', 1, glitch_timeout=10, timeout=50) #For loop check\n",
    "    if ret:\n",
    "        print('Timeout - no trigger')\n",
    "        gc.add(\"reset\")\n",
    "\n",
    "        #Device is slow to boot?\n",
    "        reboot_flush()\n",
    "\n",
    "    else:\n",
    "        if invalid_response: #fill in with invalid response detection\n",
    "            gc.add(\"reset\")\n",
    "        else:\n",
    "            if glitched_past_pw_check: # replace this\n",
    "                gc.add(\"success\")\n",
    "                print(val['payload'])\n",
    "                print(scope.glitch.width, scope.glitch.offset, scope.glitch.ext_offset)\n",
    "                print(\"🐙\", end=\"\")\n",
    "            else:\n",
    "                gc.add(\"normal\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For this lab, you may want two copies of your results; one for finding effective ext_offsets:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "results = gc.calc(ignore_params=[\"width\", \"offset\"], sort=\"success_rate\")\n",
    "results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And one for your width/offset settings:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "results = gc.calc(ignore_params=[\"ext_offset\"], sort=\"success_rate\")\n",
    "results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.dis()\n",
    "target.dis()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
